﻿#pragma once


#include <ctime>
#include <assert.h>

#include <log4lite/t_string.h>
#include <log4lite/platform_config.h>

#if defined(LOG4LITE_HAVE_FTIME)
#include <sys/timeb.h>
#endif

#if defined(LOG4LITE_HAVE_GETTIMEOFDAY)
#include <sys/time.h>
#endif

namespace log4lite {
	namespace helpers {
		
		/// 微秒
		const int ONE_SEC_IN_USEC = 1000000;

		/// 跨平台时间类，记录日志时间
		/**
		 * 提供微秒精度
		 */
		class LogTime {
		public:
			LogTime()
				: _tv_sec(0)
				, _tv_usec(0)
			{
				//
			}

			LogTime(time_t tv_sec, long tv_usec)
				: _tv_sec(tv_sec)
				, _tv_usec(tv_usec)
			{
				assert(tv_usec < ONE_SEC_IN_USEC);
			}

			
			/**
			 * 获取当前系统时间
			 */
			static LogTime gettimeofday()
			{
#if defined(LOG4LITE_HAVE_GETTIMEOFDAY)
				timeval tp;
				::gettimeofday(&tp, 0);
				return LogTime(tp.tv_sec, tp.tv_usec);
#elif defined(LOG4LITE_HAVE_FTIME)
				struct timeb tp;
				::ftime(&tp);
				return LogTime(tp.time, tp.millitm * 1000);
#else
#warning "Time::gettimeofday()- low resolution timer: gettimeofday and ftime unavailable"
				return Time(::time(0), 0);
#endif
			}

			/// 返回秒
			time_t sec() const
			{
				return _tv_sec;
			}
			/// 返回微秒
			long usec() const
			{
				return _tv_usec;
			}
			
			/// 返回格式化字符串
			/// @param [in] fmt 
			/// @return
			tstring toSting(const tstring& fmt)
			{
				struct tm time;
				localtime(&time);

				size_t len;
				tchar buffer[128] = {0};
				int buffer_size = 128;
#ifdef CHARSET_UNICODE
				len = std::wcsftime(buffer, buffer_size, fmt.c_str(), &time);
#else
				len = std::strftime(buffer, buffer_size, fmt.c_str(), &time);
#endif
				return buffer;
			}

			LogTime& operator-(const LogTime& rhs)
			{
				_tv_sec -= rhs._tv_sec;
				_tv_usec -= rhs._tv_usec;

				if(_tv_usec < 0) {
					--_tv_sec;
					_tv_usec += ONE_SEC_IN_USEC;
				}
				return *this;
			}



		private:
			void gmtime(tm* t) const
			{
				time_t clock = _tv_sec;
				tm* tmp = std::gmtime(&clock);
				*t = *tmp;
			}

			void localtime(tm* t) const
			{
				time_t clock = _tv_sec;
				tm* tmp = std::localtime(&clock);
				*t = *tmp;
			}

		private:
			time_t	_tv_sec;  /* seconds */
			long	_tv_usec;  /* microseconds */
		};
	}
}